/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.das.commonmodel.json.model;


import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.inspur.edp.cef.designtime.api.variable.CommonVariableEntity;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.das.commonmodel.entity.GspCommonModel;
import com.inspur.edp.das.commonmodel.entity.GspCommonObject;
import com.inspur.edp.cef.designtime.api.json.CefNames;
import com.inspur.edp.cef.designtime.api.json.SerializerUtils;
import com.inspur.edp.cef.designtime.api.json.Variable.CommonVariableEntityDeseriazlier;
import com.inspur.edp.das.commonmodel.entity.VersionControlInfo;
import com.inspur.edp.das.commonmodel.json.CommonModelNames;
import com.inspur.edp.das.commonmodel.json.object.CmObjectDeserializer;
import com.inspur.edp.das.commonmodel.util.HandleAssemblyNameUtil;


import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import static com.fasterxml.jackson.core.JsonToken.FIELD_NAME;

/**
 * The Json Deserializer Of Common Model
 *
 * @ClassName: CommonModelDeserializer
 * @Author: Benjamin Gong
 * @Date: 2021/1/11 17:13
 * @Version: V1.0
 */
public abstract class CommonModelDeserializer extends JsonDeserializer<GspCommonModel> {

	protected abstract void beforeCMModelDeserializer(GspCommonModel model);

	@Override
	public GspCommonModel deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
		return deserializeCommonModel(jsonParser);
	}


	public GspCommonModel deserializeCommonModel(JsonParser jsonParser) {
		GspCommonModel model = createCommonModel();
		model.setIsUseNamespaceConfig(true);
		model.setIsVirtual(false);
		model.setEntityType("");
		VersionControlInfo versionControlInfo = new VersionControlInfo();
		versionControlInfo.setVersionControlElementId("");
		model.setVersionContronInfo(versionControlInfo);
        model.setBeLabel(new ArrayList<>());
        model.setSimplifyGen(false);
        model.setSimpBeanConfig(false);
		SerializerUtils.readStartObject(jsonParser);

		beforeCMModelDeserializer(model);

		while (jsonParser.getCurrentToken() == FIELD_NAME) {
			String propName = SerializerUtils.readPropertyName(jsonParser);
			readPropertyValue(model, propName, jsonParser);
		}
		SerializerUtils.readEndObject(jsonParser);
		afterReadModel(model);
		if(model.getI18nResourceInfoPrefix()==null||"".equals(model.getI18nResourceInfoPrefix())){
			model.setI18nResourceInfoPrefix(model.getDotnetGeneratingAssembly()+"."+model.getCode());
		}

		return model;
	}


	private void afterReadModel(GspCommonModel model) {
		if (model.getVariables() != null) {
			CommonVariableEntity varEntity = model.getVariables();
			varEntity.setName(String.format("%1$s变量", model.getName()));
			varEntity.setCode(String.format("%1$sVariable", model.getCode()));
			varEntity.setParentApiAssemblyInfo(model.getApiNamespace());
			varEntity.setParentCoreAssemblyInfo(model.getCoreAssemblyInfo());
			varEntity.setParentEntityAssemblyInfo(model.getEntityAssemblyInfo());
		}
	}

	private void readPropertyValue(GspCommonModel model, String propName, JsonParser jsonParser) {
		switch (propName) {
			case CommonModelNames.ID:
				model.setID(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CommonModelNames.Code:
				model.setCode(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CommonModelNames.Flag:
				model.setFlag(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CommonModelNames.Name:
				model.setName(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CommonModelNames.DESCRIPTION:
				model.setDescription(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CommonModelNames.BeLabel:
				model.setBeLabel(SerializerUtils.readStringArray(jsonParser));
				break;
			case CommonModelNames.IsVirtual:
				model.setIsVirtual(SerializerUtils.readPropertyValue_boolean(jsonParser));
				break;
			case CommonModelNames.EntityType:
				model.setEntityType(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CommonModelNames.PrimayKeyID:
				SerializerUtils.readPropertyValue_String(jsonParser);
				break;
			case CommonModelNames.MainObject:
				readMainObject(jsonParser, model);
				break;
			case CommonModelNames.Variables:
				readVariables(jsonParser, model);
				break;
			case CommonModelNames.ExtendNodeList:
				readExtendNodeList(jsonParser, model);
				break;
			case CommonModelNames.FkConstraints:
				readFkConstraints(jsonParser, model);
				break;
			case CommonModelNames.ExtProperties:
				readExtProperties(jsonParser, model);
				break;
			case CommonModelNames.GeneratingAssembly:
				String tempValue=SerializerUtils.readPropertyValue_String(jsonParser);
				model.setDotnetGeneratingAssembly(tempValue);
				model.setGeneratingAssembly(handleGeneratingAssembly(tempValue));
				break;
			case CefNames.I18nResourceInfoPrefix:
				model.setI18nResourceInfoPrefix(SerializerUtils.readPropertyValue_String(jsonParser));
				break;
			case CommonModelNames.IsUseNamespaceConfig:
				model.setIsUseNamespaceConfig(SerializerUtils.readPropertyValue_boolean(jsonParser));
				break;
			case CommonModelNames.VersionControlInfo:
				model.setVersionContronInfo(readVersionControlInfo(jsonParser));
				break;
			case CommonModelNames.IsSimplifyGen:
				model.setSimplifyGen(SerializerUtils.readPropertyValue_boolean(jsonParser));
				break;
			case CommonModelNames.IsSimpBeanConfig:
				model.setSimpBeanConfig(SerializerUtils.readPropertyValue_boolean(jsonParser));
				break;
			default:
				if (!readExtendModelProperty(model, propName, jsonParser)) {
					throw new RuntimeException(String.format("%s%s%s", "GspCommonDataTypeDeserializer未识别的属性名：", propName, "。请将系统补丁升级至可更新范围内最新。"));
				}
		}
	}

	private VersionControlInfo readVersionControlInfo(JsonParser jsonParser) {
		VersionControlInfo info = new VersionControlInfo();
		if (SerializerUtils.readNullObject(jsonParser)) {
			return info;
		}
		SerializerUtils.readStartObject(jsonParser);
		SerializerUtils.readPropertyName(jsonParser);
		info.setVersionControlElementId(SerializerUtils.readPropertyValue_String(jsonParser));
		SerializerUtils.readEndObject(jsonParser);
		return info;
	}

	private String handleGeneratingAssembly(String readPropertyValue_string) {
		return HandleAssemblyNameUtil.convertToJavaPackageName(readPropertyValue_string);
	}

	private void readExtProperties(JsonParser jsonParser, GspCommonModel model) {
		//后端文件没有序列化该属性
	}

	private void readFkConstraints(JsonParser jsonParser, GspCommonModel model) {
		SerializerUtils.readStartArray(jsonParser);
		SerializerUtils.readEndArray(jsonParser);
	}

	private void readExtendNodeList(JsonParser reader, GspCommonModel model) {
		SerializerUtils.readStartArray(reader);
		while (reader.getCurrentToken() == JsonToken.START_OBJECT) {
			SerializerUtils.readStartObject(reader);
			String key = SerializerUtils.readPropertyValue_String(reader);
			String value = SerializerUtils.readPropertyValue_String(reader);
			model.getExtendNodeList().put(key, value);
			SerializerUtils.readEndObject(reader);
		}
		SerializerUtils.readEndArray(reader);
	}

	private void readVariables(JsonParser jsonParser, GspCommonModel model) {
		CommonVariableEntityDeseriazlier deseriazlier = new CommonVariableEntityDeseriazlier();
		CommonVariableEntity entity = (CommonVariableEntity) deseriazlier.deserializeCommonDataType(jsonParser);
		model.setVariables(entity);
	}

	private void readMainObject(JsonParser jsonParser, GspCommonModel model) {
		CmObjectDeserializer deserializer = createCmObjectDeserializer();
		deserializer.setFlag(model.getFlag());
		GspCommonObject mainObj = (GspCommonObject) deserializer.deserializeCommonDataType(jsonParser);
		if (mainObj != null) {
			mainObj.setBelongModel(model);
			mainObj.setBelongModelID(model.getID());
			setChildObjedtBelongModel(mainObj, model);
		}
		model.setMainObject(mainObj);
	}

	private void setChildObjedtBelongModel(IGspCommonObject parentObject, GspCommonModel cm) {
		if (parentObject == null || parentObject.getContainChildObjects() == null || parentObject.getContainChildObjects().size() == 0) {
			return;
		}
		for (IGspCommonObject childObject : parentObject.getContainChildObjects()) {
			childObject.setBelongModel(cm);
			childObject.setBelongModelID(cm.getID());
			// 递归
			setChildObjedtBelongModel(childObject, cm);
		}
	}

	protected boolean readExtendModelProperty(GspCommonModel model, String propName, JsonParser jsonParser) {
		return false;
	}
	protected abstract GspCommonModel createCommonModel();

	protected abstract CmObjectDeserializer createCmObjectDeserializer();
}
